home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / LinAlg 3.1 / LinAlg / vmatrix.cc < prev    next >
Encoding:
Text File  |  1995-12-20  |  14.9 KB  |  523 lines  |  [TEXT/ALFA]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *          Verify Primitive Operations on Matrices
  6.  *    (creation, special cases and element-by-element operations)
  7.  *
  8.  *
  9.  * $Id: vmatrix.cc,v 3.1 1995/02/03 15:24:27 oleg Exp oleg $
  10.  *
  11.  ************************************************************************
  12.  */
  13.  
  14. #include "LinAlg.h"
  15. #include "builtin.h"
  16. #include <math.h>
  17. #include <iostream.h>
  18. #include <float.h>
  19.  
  20. /*
  21.  *------------------------------------------------------------------------
  22.  *       Test allocation functions and compatibility check
  23.  */
  24.  
  25. static void test_allocation(void)
  26. {
  27.  
  28.   cout << "\n\n---> Test allocation and compatibility check\n";
  29.  
  30.   Matrix m1(4,20);    m1.set_name("Matrix m1");
  31.   Matrix m2(1,4,1,20);    m2.set_name("Matrix m2");
  32.   Matrix m3(1,4,0,19);    m3.set_name("Matrix m3");
  33.   Matrix m4(m1);    m4.set_name("Matrix m4");
  34.   cout << "The following matrices have been allocated\n";
  35.   m1.info(), m2.info(), m3.info(), m4.info();
  36.  
  37.   cout << "\nStatus information reported for matrix m3:\n";
  38.   cout << "  Row lower bound ... " << m3.q_row_lwb() << "\n";
  39.   cout << "  Row upper bound ... " << m3.q_row_upb() << "\n";
  40.   cout << "  Col lower bound ... " << m3.q_col_lwb() << "\n";
  41.   cout << "  Col upper bound ... " << m3.q_col_upb() << "\n";
  42.   cout << "  No. rows ..........." << m3.q_nrows() << "\n";
  43.   cout << "  No. cols ..........." << m3.q_ncols() << "\n";
  44.   cout << "  No. of elements ...." << m3.q_no_elems() << "\n";
  45.   cout << "  Name " << m3.q_name() << "\n";
  46.  
  47.   cout << "\nCheck matrices 1 & 2 for compatibility\n";
  48.   are_compatible(m1,m2);
  49.  
  50.   cout << "Check matrices 1 & 4 for compatibility\n";
  51.   are_compatible(m1,m4);
  52.  
  53. #if 0
  54.   cout << "Check matrices 1 & 3 for compatibility\n";
  55.   are_compatible(m1,m3);
  56. #endif
  57.  
  58.   cout << "m2 has to be compatible with m3 after resizing to m3\n";
  59.   m2.resize_to(m3);
  60.   are_compatible(m2,m3);
  61.  
  62.   Matrix m5(m1.q_nrows()+1,m1.q_ncols()+5); m5.set_name("Matrix m5");
  63.   cout << "m1 has to be compatible with m5 after resizing to m5\n";
  64.   m5.info();
  65.   m1.resize_to(m5.q_nrows(),m5.q_ncols());
  66.   are_compatible(m1,m5);
  67.  
  68. }
  69.  
  70. /*
  71.  *------------------------------------------------------------------------
  72.  *             Test uniform element operations
  73.  */
  74.  
  75. static void test_element_op(const int rsize, const int csize)
  76. {
  77.   const double pattern = 8.625;
  78.   register int i,j;
  79.  
  80.   cout << "\n\n---> Test operations that treat each element uniformly\n";
  81.  
  82.   Matrix m(-1,rsize-2,1,csize);
  83.  
  84.   cout << "Writing zeros to m...\n";
  85.   for(i=m.q_row_lwb(); i<=m.q_row_upb(); i++)
  86.     for(j=m.q_col_lwb(); j<=m.q_col_upb(); j++)
  87.       m(i,j) = 0;
  88.   verify_element_value(m,0);
  89.  
  90.   cout << "Creating zero m1 ...\n";
  91.   Matrix m1(Matrix::Zero,m);
  92.   verify_element_value(m1,0);
  93.  
  94.   cout << "Comparing m1 with 0 ...\n";
  95.   assure(m1 == 0, "m1 is not zero!");
  96.   assure(!(m1 != 0), "m1 is not zero!");
  97.  
  98.   cout << "Writing a pattern " << pattern << " by assigning to m(i,j)...\n";
  99.   for(i=m.q_row_lwb(); i<=m.q_row_upb(); i++)
  100.     for(j=m.q_col_lwb(); j<=m.q_col_upb(); j++)
  101.       m(i,j) = pattern;
  102.   verify_element_value(m,pattern);
  103.  
  104.   cout << "Writing the pattern by assigning to m1 as a whole ...\n";
  105.   m1 = pattern;
  106.   verify_element_value(m1,pattern);
  107.  
  108.   cout << "Comparing m and m1 ...\n";
  109.   assure(m == m1, "m and m1 are unexpectedly different!");
  110.   cout << "Comparing (m=0) and m1 ...\n";
  111.   assert(!(m.clear() == m1));
  112.  
  113.   cout << "Clearing m1 ...\n";
  114.   m1.clear();
  115.   verify_element_value(m1,0);
  116.  
  117.   cout << "\nClear m and add the pattern\n";
  118.   m.clear();
  119.   m += pattern;
  120.   verify_element_value(m,pattern);
  121.   cout << "   add the doubled pattern with the negative sign\n";
  122.   m += -2*pattern;
  123.   verify_element_value(m,-pattern);
  124.   cout << "   subtract the trippled pattern with the negative sign\n";
  125.   m -= -3*pattern;
  126.   verify_element_value(m,2*pattern);
  127.  
  128.   cout << "\nVerify comparison operations when all elems are the same\n";
  129.   m = pattern;
  130.   assert( m == pattern && !(m != pattern) );
  131.   assert( m > 0 && m >= pattern && m <= pattern );
  132.   assert( m > -pattern && m >= -pattern );
  133.   assert( m <= pattern && !(m < pattern) );
  134.   m -= 2*pattern;
  135.   assert( m  < -pattern/2 && m <= -pattern/2 );
  136.   assert( m  >= -pattern && !(m > -pattern) );
  137.  
  138.   cout << "\nVerify comparison operations when not all elems are the same\n";
  139.   m = pattern; m(m.q_row_upb(),m.q_col_upb()) = pattern-1;
  140.   assert( !(m == pattern) && !(m != pattern) );
  141.   assert( m != 0 );         // none of elements are 0
  142.   assert( !(m >= pattern) && m <= pattern && !(m<pattern) );
  143.   assert( !(m <= pattern-1) && m >= pattern-1 && !(m>pattern-1) );
  144.  
  145.   cout << "\nAssign 2*pattern to m by repeating additions\n";
  146.   m = 0; m += pattern; m += pattern;
  147.   cout << "Assign 2*pattern to m1 by multiplying by two \n";
  148.   m1 = pattern; m1 *= 2;
  149.   verify_element_value(m1,2*pattern);
  150.   assert( m == m1 );
  151.   cout << "Multiply m1 by one half returning it to the 1*pattern\n";
  152.   m1 *= 1/2.;
  153.   verify_element_value(m1,pattern);
  154.  
  155.   cout << "\nAssign -pattern to m and m1\n";
  156.   m.clear(); m -= pattern; m1 = -pattern;
  157.   verify_element_value(m,-pattern);
  158.   assert( m == m1 );
  159.   cout << "m = sqrt(sqr(m)); m1 = abs(m1); Now m and m1 have to be the same\n";
  160.   m.sqr();
  161.   verify_element_value(m,pattern*pattern);
  162.   m.sqrt();
  163.   verify_element_value(m,pattern);
  164.   m1.abs();
  165.   verify_element_value(m1,pattern);
  166.   assert( m == m1 );
  167.  
  168.   cout << "\nCheck out to see that sin^2(x) + cos^2(x) = 1\n";
  169.   class FillMatrix : public ElementAction
  170.   {
  171.     int no_elems, no_cols;
  172.     void operation(REAL& element)
  173.         { element = 4*M_PI/no_elems * (i*no_cols+j); }
  174.     public: FillMatrix(const Matrix& m) :
  175.             no_elems(m.q_no_elems()), no_cols(m.q_ncols()) {}
  176.   };
  177.   m.apply(FillMatrix(m));
  178.   m1 = m;
  179.   class ApplyFunction : public ElementPrimAction
  180.   {
  181.     double (*func)(const double x);
  182.     void operation(REAL& element) { element = func(element); }
  183.     public: ApplyFunction(double (*_func)(const double x)) : func(_func) {}
  184.   };
  185.   m.apply(ApplyFunction(sin));
  186.   m1.apply(ApplyFunction(cos));
  187.   m.sqr();
  188.   m1.sqr();
  189.   m += m1;
  190.   verify_element_value(m,1);
  191.  
  192.   cout << "\nDone\n\n";
  193. }
  194.  
  195. /*
  196.  *------------------------------------------------------------------------
  197.  *          Test binary matrix element-by-element operations
  198.  */
  199.  
  200. static void test_binary_ebe_op(const int rsize, const int csize)
  201. {
  202.   const double pattern = 4.25;
  203.   register int i,j;
  204.  
  205.   cout << "\n---> Test Binary Matrix element-by-element operations\n";
  206.  
  207.   Matrix m(2,rsize+1,0,csize-1);
  208.   Matrix m1(Matrix::Zero,m);
  209.   Matrix mp(Matrix::Zero,m);
  210.  
  211.   for(i=mp.q_row_lwb(); i<=mp.q_row_upb(); i++)
  212.     for(j=mp.q_col_lwb(); j<=mp.q_col_upb(); j++)
  213.       mp(i,j) = (i-m.q_nrows()/2.)*j*pattern;
  214.   
  215.  
  216.   cout << "\nVerify assignment of a matrix to the matrix\n";
  217.   m = pattern;
  218.   m1.clear();
  219.   m1 = m;
  220.   verify_element_value(m1,pattern);
  221.   assert( m1 == m );
  222.  
  223.   cout << "\nAdding the matrix to itself, uniform pattern " << pattern << "\n";
  224.   m.clear(); m = pattern;
  225.   m1 = m; m1 += m1;
  226.   verify_element_value(m1,2*pattern);
  227.   cout << "  subtracting two matrices ...\n";
  228.   m1 -= m;
  229.   verify_element_value(m1,pattern);
  230.   cout << "  subtracting the matrix from itself\n";
  231.   m1 -= m1;
  232.   verify_element_value(m1,0);
  233.   cout << "  adding two matrices together\n";
  234.   m1 += m;
  235.   verify_element_value(m1,pattern);
  236.  
  237.   cout << "\nArithmetic operations on matrices with not the same elements\n";
  238.   cout << "   adding mp to the zero matrix...\n";
  239.   m.clear(); m += mp;
  240.   verify_matrix_identity(m,mp);
  241.   m1 = m;
  242.   cout << "   making m = 3*mp and m1 = 3*mp, via add() and succesive mult\n";
  243.   add(m,2,mp);
  244.   m1 += m1; m1 += mp;
  245.   verify_matrix_identity(m,m1);
  246.   cout << "   clear both m and m1, by subtracting from itself and via add()\n";
  247.   m1 -= m1;
  248.   add(m,-3,mp);
  249.   verify_matrix_identity(m,m1);
  250.  
  251.   cout << "\nTesting element-by-element multiplications and divisions\n";
  252.   cout << "   squaring each element with sqr() and via multiplication\n";
  253.   m = mp; m1 = mp;
  254.   m.sqr();
  255.   element_mult(m1,m1);
  256.   verify_matrix_identity(m,m1);
  257.   cout << "   compare (m = pattern^2)/pattern with pattern\n";
  258.   m = pattern; m1 = pattern;
  259.   m.sqr();
  260.   element_div(m,m1);
  261.   verify_element_value(m,pattern);
  262.   compare(m1,m,"Original vector and vector after squaring and dividing");
  263.  
  264.   cout << "\nDone\n";
  265. }
  266.  
  267. /*
  268.  *------------------------------------------------------------------------
  269.  *               Verify matrix transposition
  270.  */
  271.  
  272. static void test_transposition(const int msize)
  273. {
  274.   cout << "\n---> Verify matrix transpose\n"
  275.           "for matrices of a characteristic size " << msize << endl;
  276.  
  277.   {
  278.     cout << "\nCheck to see that a square UnitMatrix' stays the same";
  279.     Matrix m(msize,msize);
  280.     m.unit_matrix();
  281.     Matrix mt(Matrix::Transposed,m);
  282.     assert( m == mt );
  283.   }
  284.   
  285.   {
  286.     cout << "\nTest a non-square UnitMatrix";
  287.     Matrix m(msize,msize+1);
  288.     m.unit_matrix();
  289.     Matrix mt(Matrix::Transposed,m);
  290.     assert( m.q_nrows() == mt.q_ncols() && m.q_ncols() == mt.q_nrows() );
  291.     register int i,j;
  292.     for(i=m.q_row_lwb(); i<=min(m.q_row_upb(),m.q_col_upb()); i++)
  293.       for(j=m.q_col_lwb(); j<=min(m.q_row_upb(),m.q_col_upb()); j++)
  294.     assert( m(i,j) == mt(i,j) );
  295.   }
  296.  
  297.   {
  298.     cout << "\nCheck to see that a symmetric (Hilbert)Matrix' stays the same";
  299.     Matrix m(msize,msize);
  300.     m.hilbert_matrix();
  301.     Matrix mt(Matrix::Transposed,m);
  302.     assert( m == mt );
  303.   }
  304.  
  305.   {
  306.     cout << "\nCheck transposing a non-symmetric matrix";
  307.     Matrix m(msize+1,msize);
  308.     m.hilbert_matrix();
  309.     m(1,2) = M_PI;
  310.     Matrix mt(Matrix::Transposed,m);
  311.     assert( m.q_nrows() == mt.q_ncols() && m.q_ncols() == mt.q_nrows() );
  312.     assert( mt(2,1) == (REAL)M_PI && mt(1,2) != (REAL)M_PI );
  313.  
  314.     cout << "\nCheck double transposing a non-symmetric matrix";
  315.     Matrix mtt(Matrix::Transposed,mt);
  316.     assert( m == mtt );
  317.   }
  318.  
  319.   cout << "\nDone\n";
  320. }
  321.  
  322. /*
  323.  *------------------------------------------------------------------------
  324.  *            Test special matrix creation
  325.  */
  326.  
  327. static void test_special_creation(const int dim)
  328. {
  329.   cout << "\n---> Check creating some special matrices of dimension " <<
  330.     dim << "\n\n";
  331.  
  332.   {
  333.     cout << "test creating Hilbert matrices" << endl;
  334.     Matrix m(dim+1,dim);
  335.     Matrix m1(Matrix::Zero,m);
  336.     m.hilbert_matrix();
  337.     assert( !(m == m1) );
  338.     assert( m != 0 );
  339.     class MakeHilbert : public ElementAction
  340.     {
  341.       void operation(REAL& element) { element = 1./(i+j-1); }
  342.       public: MakeHilbert(void) {}
  343.     };
  344.     m1.apply(MakeHilbert());
  345.     assert( m1 != 0 );
  346.     assert( m == m1 );
  347.   }
  348.  
  349.   {
  350.     cout << "test creating zero matrix and copy constructor" << endl;
  351.     Matrix m(dim,dim+1);
  352.     m.hilbert_matrix();
  353.     assert( m != 0 );
  354.     Matrix m1(m);            // Applying the copy constructor
  355.     assert( m1 == m );
  356.     Matrix m2(Matrix::Zero,m);
  357.     assert( m2 == 0 );
  358.     assert( m != 0 );
  359.   }
  360.  
  361.   {
  362.     cout << "test creating unit matrices" << endl;
  363.     class TestUnit : public ElementAction
  364.     {
  365.       int is_unit;
  366.       void operation(REAL& element)
  367.       { if( is_unit ) is_unit = i==j ? element == 1.0 : element == 0; }
  368.       public: TestUnit(void) : is_unit(0==0) {}
  369.       int is_indeed_unit(void) const         { return is_unit; }
  370.     };
  371.     Matrix m(dim,dim);
  372.     {
  373.       TestUnit test_unit;
  374.       m.apply(test_unit);
  375.       assert( !test_unit.is_indeed_unit() );
  376.     }
  377.     m.unit_matrix();
  378.     {
  379.       TestUnit test_unit;
  380.       m.apply(test_unit);
  381.       assert( test_unit.is_indeed_unit() );
  382.     }
  383.     m.resize_to(dim-1,dim);
  384.     Matrix m2(Matrix::Unit,m);
  385.     {
  386.       TestUnit test_unit;
  387.       m2.apply(test_unit);
  388.       assert( test_unit.is_indeed_unit() );
  389.     }
  390.     m.resize_to(dim,dim-2);
  391.     m.unit_matrix();
  392.     {
  393.       TestUnit test_unit;
  394.       m.apply(test_unit);
  395.       assert( test_unit.is_indeed_unit() );
  396.     }
  397.   }
  398.  
  399.   {
  400.     cout << "check to see that Haar matrix has *exactly* orthogonal columns"
  401.                     << endl;
  402.     const int order = 5;
  403.     Matrix haar = haar_matrix(order);
  404.     assert( haar.q_nrows() == (1<<order) && haar.q_nrows() == haar.q_ncols() );
  405.     Vector colj(1<<order), coll(1<<order);
  406.     register int j;
  407.     for(j=haar.q_col_lwb(); j<=haar.q_col_upb(); j++)
  408.     {
  409.       colj = MatrixColumn(haar,j);
  410.       assert( fabs(abs(colj*colj - 1.0)) <= FLT_EPSILON );
  411.       for(register int l=j+1; l<=haar.q_col_upb(); l++)
  412.       {
  413.     coll = MatrixColumn(haar,l);
  414.     assert( colj*coll == 0 );
  415.       }
  416.     }
  417.     cout << "make Haar (sub)matrix and test it *is* a submatrix" << endl;
  418.     const int no_sub_cols = (1<<order) - 3;
  419.     Matrix haar_sub = haar_matrix(order,no_sub_cols);
  420.     assert( haar_sub.q_nrows() == (1<<order) && 
  421.         haar_sub.q_ncols() == no_sub_cols );
  422.     for(j=haar_sub.q_col_lwb(); j<=haar_sub.q_col_upb(); j++)
  423.     {
  424.       colj = MatrixColumn(haar,j);
  425.       coll = MatrixColumn(haar_sub,j);
  426.       verify_matrix_identity(colj,coll);
  427.     }
  428.   }
  429.  
  430.   cout << "\nDone\n";
  431. }
  432.  
  433.  
  434. static void test_matrix_promises(const int dim)
  435. {
  436.   cout << "\n---> Check making/forcing promises, (lazy)matrices of dimension " <<
  437.     dim << "\n\n";
  438.  
  439.   class hilbert_matrix_promise : public LazyMatrix
  440.   {
  441.     void fill_in(Matrix& m) const { m.hilbert_matrix(); }
  442.   public:
  443.     hilbert_matrix_promise(const int nrows, const int ncols)
  444.     : LazyMatrix(nrows,ncols) {}
  445.     hilbert_matrix_promise(const int _row_lwb, const int _row_upb,
  446.          const int _col_lwb, const int _col_upb)
  447.     : LazyMatrix(_row_lwb,_row_upb,_col_lwb,_col_upb) {}
  448.   };
  449.   
  450.   {
  451.     cout << "make a promise and force it by a constructor" << endl;
  452.     Matrix m = hilbert_matrix_promise(dim,dim+1);
  453.     Matrix m1(Matrix::Zero,m);
  454.     assert( !(m1 == m) && m1 == 0 );
  455.     m1.hilbert_matrix();
  456.     verify_matrix_identity(m,m1);
  457.   }
  458.   
  459.   {
  460.     cout << "make a promise and force it by an assignment" << endl;
  461.     Matrix m(-1,dim,0,dim);
  462.     Matrix m1(Matrix::Zero,m);
  463.     m = hilbert_matrix_promise(-1,dim,0,dim);
  464.     assert( !(m1 == m) && m1 == 0 );
  465.     m1.hilbert_matrix();
  466.     verify_matrix_identity(m,m1);
  467.   }
  468.  
  469.   cout << "\nDone\n";
  470. }
  471.  
  472. /*
  473.  *------------------------------------------------------------------------
  474.  *            Verify the norm calculation
  475.  */
  476.  
  477. static void test_norms(const int rsize, const int csize)
  478. {
  479.   cout << "\n---> Verify norm calculations\n";
  480.  
  481.   const double pattern = 10.25;
  482.  
  483.   if( rsize % 2 == 1 || csize %2 == 1 )
  484.     _error("Sorry, size of the matrix to test must be even for this test\n");
  485.  
  486.   Matrix m(rsize,csize);
  487.  
  488.   cout << "\nAssign " << pattern << " to all the elements and check norms\n";
  489.   m = pattern;
  490.   cout << "  1. (col) norm should be pattern*nrows\n";
  491.   assert( m.norm_1() == pattern*m.q_nrows() );
  492.   assert( m.norm_1() == m.col_norm() );
  493.   cout << "  Inf (row) norm should be pattern*ncols\n";
  494.   assert( m.norm_inf() == pattern*m.q_ncols() );
  495.   assert( m.norm_inf() == m.row_norm() );
  496.   cout << "  Square of the Eucl norm has got to be pattern^2 * no_elems\n";
  497.   assert( m.e2_norm() == sqr(pattern)*m.q_no_elems() );
  498.   Matrix m1(Matrix::Zero,m);
  499.   assert( m.e2_norm() == e2_norm(m,m1) );
  500.  
  501.   cout << "\nDone\n";
  502. }
  503.  
  504. /*
  505.  *------------------------------------------------------------------------
  506.  *                Root module
  507.  */
  508.  
  509. main()
  510. {
  511.   cout << "\n\n" << _Minuses << 
  512.           "\n\t\tVerify Operations on Matrices\n";
  513.  
  514.   test_allocation();
  515.   test_element_op(20,10);
  516.   test_binary_ebe_op(10,20);
  517.   test_norms(40,20);
  518.   test_special_creation(20);
  519.   test_matrix_promises(20);
  520.   test_transposition(20);
  521. }
  522.  
  523.